package com.chucang.shucang.sms.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.chucang.shucang.common.base.constant.SecurityConstant;
import com.chucang.shucang.common.base.exception.FastException;
import com.chucang.shucang.common.base.redis.RedisUtil;
import com.chucang.shucang.common.base.utils.OpsUtil;
import com.chucang.shucang.common.base.utils.R;
import com.chucang.shucang.common.mq.constant.RabbitConstant;
import com.chucang.shucang.common.security.annotation.Inner;
import com.chucang.shucang.common.security.entity.ShuCangUser;
import com.chucang.shucang.common.security.utils.SecurityUtil;
import com.chucang.shucang.sms.constant.SmsCacheConstant;
import com.chucang.shucang.sms.constant.SmsCommonConstant;
import com.chucang.shucang.sms.entity.PanicPurchaseEntity;
import com.chucang.shucang.sms.exception.SmsErrorCode;
import com.chucang.shucang.sms.feign.UserService;
import com.chucang.shucang.sms.feign.vo.UserBaseEntity;
import com.chucang.shucang.sms.service.PanicPurchaseService;
import com.chucang.shucang.common.mq.to.BlindBoxOrderBaseTO;
import com.chucang.shucang.common.mq.to.CollectionOrderBaseTO;
import com.chucang.shucang.common.base.redis.vo.PanicPurchaseProductRedisVO;
import com.chucang.shucang.sms.vo.PanicPurchaseResVO;
import com.chucang.shucang.sms.vo.PanicPurchaseVO;
import com.github.yitter.idgen.YitIdHelper;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 商品预售表
 *
 * @author flitsneak flitsneak@gmail.com
 * @since 1.0.0 2022-09-12
 */
@RestController
@RequestMapping("/panicpurchase")
@RequiredArgsConstructor
@Api(tags = "商品预售表")
public class PanicPurchaseController {

    private final PanicPurchaseService panicPurchaseService;
    private final UserService userService;
    private final RabbitTemplate rabbitTemplate;
    private final RedissonClient redissonClient;
    private final RedisUtil redisUtil;

    /**
     * 发售抢购
     *
     * @param panicPurchaseVO ppv
     * @return r
     */
    @PostMapping("/doPurchase")
    public R<PanicPurchaseResVO> doPurchase(@Valid @RequestBody PanicPurchaseVO panicPurchaseVO) throws InterruptedException {
        if (panicPurchaseVO.getProductType().equals(SmsCommonConstant.COLLECTION)) {
            LambdaQueryWrapper<PanicPurchaseEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(PanicPurchaseEntity::getProductId, panicPurchaseVO.getProductId())
                    .eq(PanicPurchaseEntity::getProductType, panicPurchaseVO.getProductType())
                    .select();
            PanicPurchaseEntity one = panicPurchaseService.getOne(queryWrapper);
            if (Objects.isNull(one)) {
                return R.failed();
            }
            long begin = one.getStartTime().getTime();
            long end = one.getEndTime().getTime();
            long current = new Date().getTime();
            if (current > begin && current < end) {
                PanicPurchaseProductRedisVO redisVO = (PanicPurchaseProductRedisVO) redisUtil.getHashValue(SmsCacheConstant.PRE_ON_SELL_DETAILS, String.format(SmsCacheConstant.COLLECTION_ON_SHELVE, panicPurchaseVO.getProductId(), begin, end));
                //检验是否符合限制购买量
                if (panicPurchaseVO.getPurchaseNum() > redisVO.getPerLimit()) {
                    return R.failed(SmsErrorCode.EXCEED_PER_LIMIT.getCode(), SmsErrorCode.EXCEED_PER_LIMIT.getMsg());
                }
                //校验购买key
                if (CharSequenceUtil.isBlank(panicPurchaseVO.getPurchaseKey())) {
                    return R.failed(SmsErrorCode.PURCHASE_NOT_START.getCode(), SmsErrorCode.PURCHASE_NOT_START.getMsg());
                }
                ShuCangUser user = SecurityUtil.getUser();
                if (Objects.isNull(user)) {
                    return R.failed();
                }
                Long userId = user.getId();
                //校验用户是否实名认证
                if (user.getIsRealAuth() != SmsCommonConstant.REAL_NAME_AUTH) {
                    R<UserBaseEntity> baseInfoById = userService.getUserBaseInfoById(userId, SecurityConstant.FROM_IN);
                    UserBaseEntity userBaseEntity = OpsUtil.of(baseInfoById)
                            .assertDataNotNull(e -> new FastException("获取用户信息错误！"))
                            .getData()
                            .get();
                    if (userBaseEntity.getIsRealAuth() != SmsCommonConstant.REAL_NAME_AUTH) {
                        return R.failed(SmsErrorCode.NO_REAL_NAME_AUTH.getCode(), SmsErrorCode.NO_REAL_NAME_AUTH.getMsg());
                    }
                }
                //满足购买条件
                //防止二次购买
                String userKey = userId.toString() + panicPurchaseVO.getProductId();
                long ttl = end - current;
                if (redisUtil.setIfAbsent(userKey, panicPurchaseVO.getPurchaseNum().toString(), ttl, TimeUnit.MILLISECONDS)) {
                    //开始购买
                    RSemaphore semaphore = redissonClient.getSemaphore(String.format(SmsCacheConstant.PRE_ON_SELL_STOCK, redisVO.getToken()));
                    if (semaphore.tryAcquire(panicPurchaseVO.getPurchaseNum(), 100, TimeUnit.MILLISECONDS)) {
                        //创建订单，发送到订单服务
                        long orderId = YitIdHelper.nextId();
                        CollectionOrderBaseTO collectionOrderBaseTO = new CollectionOrderBaseTO();
                        collectionOrderBaseTO.setId(orderId);
                        collectionOrderBaseTO.setCollectionId(panicPurchaseVO.getProductId());
                        BigDecimal num = new BigDecimal(panicPurchaseVO.getPurchaseNum());
                        BigDecimal totalAmount = redisVO.getProductPrice().multiply(num);
                        collectionOrderBaseTO.setOrderAmount(totalAmount);
                        long sub = userId % 1000000;
                        String orderSn = String.valueOf(orderId) + sub;
                        collectionOrderBaseTO.setOrderSn(orderSn);
                        collectionOrderBaseTO.setUserId(userId);
                        collectionOrderBaseTO.setOrderType(SmsCommonConstant.PANIC_PURCHASE);
                        collectionOrderBaseTO.setOrderNum(panicPurchaseVO.getPurchaseNum());

                        rabbitTemplate.convertAndSend(RabbitConstant.ORDER_EXCHANGE, RabbitConstant.PANIC_PURCHASE_KEY, collectionOrderBaseTO);
                        //死信队列
                        rabbitTemplate.convertAndSend(RabbitConstant.ORDER_EXCHANGE, RabbitConstant.PANIC_PURCHASE_DELAY_KEY, collectionOrderBaseTO);

                        PanicPurchaseResVO panicPurchaseResVO = new PanicPurchaseResVO();
                        panicPurchaseResVO.setOrderSn(orderSn);
                        panicPurchaseResVO.setProductType(SmsCommonConstant.COLLECTION);
                        return R.ok(panicPurchaseResVO);
                    }
                } else {
                    return R.failed(SmsErrorCode.OUT_OF_TEAM.getCode(), SmsErrorCode.OUT_OF_TEAM.getMsg());
                }
            } else {
                return R.failed(SmsErrorCode.PURCHASE_NOT_START.getCode(), SmsErrorCode.PURCHASE_NOT_START.getMsg());
            }

        } else if (panicPurchaseVO.getProductType().equals(SmsCommonConstant.BLIND_BOX)) {
            LambdaQueryWrapper<PanicPurchaseEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(PanicPurchaseEntity::getProductId, panicPurchaseVO.getProductId())
                    .eq(PanicPurchaseEntity::getProductType, panicPurchaseVO.getProductType())
                    .select();
            PanicPurchaseEntity one = panicPurchaseService.getOne(queryWrapper);
            if (Objects.isNull(one)) {
                return R.failed();
            }
            long begin = one.getStartTime().getTime();
            long end = one.getEndTime().getTime();
            long current = new Date().getTime();
            if (current > begin && current < end) {
                PanicPurchaseProductRedisVO redisVO = (PanicPurchaseProductRedisVO) redisUtil.getHashValue(SmsCacheConstant.PRE_ON_SELL_DETAILS, String.format(SmsCacheConstant.BLIND_BOX_ON_SHELVE, panicPurchaseVO.getProductId(), begin, end));
                //检验是否符合限制购买量
                if (panicPurchaseVO.getPurchaseNum() > redisVO.getPerLimit()) {
                    return R.failed(SmsErrorCode.EXCEED_PER_LIMIT.getCode(), SmsErrorCode.EXCEED_PER_LIMIT.getMsg());
                }
                //校验购买key
                if (CharSequenceUtil.isBlank(panicPurchaseVO.getPurchaseKey())) {
                    return R.failed(SmsErrorCode.PURCHASE_NOT_START.getCode(), SmsErrorCode.PURCHASE_NOT_START.getMsg());
                }
                ShuCangUser user = SecurityUtil.getUser();
                if (Objects.isNull(user)) {
                    return R.failed();
                }
                Long userId = user.getId();
                //校验用户是否实名认证
                if (user.getIsRealAuth() != SmsCommonConstant.REAL_NAME_AUTH) {
                    R<UserBaseEntity> baseInfoById = userService.getUserBaseInfoById(userId, SecurityConstant.FROM_IN);
                    UserBaseEntity userBaseEntity = OpsUtil.of(baseInfoById)
                            .assertDataNotNull(e -> new FastException("获取用户信息错误！"))
                            .getData()
                            .get();
                    if (userBaseEntity.getIsRealAuth() != SmsCommonConstant.REAL_NAME_AUTH) {
                        return R.failed(SmsErrorCode.NO_REAL_NAME_AUTH.getCode(), SmsErrorCode.NO_REAL_NAME_AUTH.getMsg());
                    }
                }
                //满足购买条件
                //防止二次购买
                String userKey = userId.toString() + panicPurchaseVO.getProductId();
                long ttl = end - current;
                if (redisUtil.setIfAbsent(userKey, panicPurchaseVO.getPurchaseNum().toString(), ttl, TimeUnit.MILLISECONDS)) {
                    //开始购买
                    RSemaphore semaphore = redissonClient.getSemaphore(String.format(SmsCacheConstant.PRE_ON_SELL_STOCK, redisVO.getToken()));
                    if (semaphore.tryAcquire(panicPurchaseVO.getPurchaseNum(), 100, TimeUnit.MILLISECONDS)) {
                        //创建订单，发送到订单服务
                        long orderId = YitIdHelper.nextId();
                        BlindBoxOrderBaseTO blindBoxOrderBaseTO = new BlindBoxOrderBaseTO();
                        blindBoxOrderBaseTO.setId(orderId);
                        blindBoxOrderBaseTO.setBbId(panicPurchaseVO.getProductId());
                        BigDecimal num = new BigDecimal(panicPurchaseVO.getPurchaseNum());
                        BigDecimal totalAmount = redisVO.getProductPrice().multiply(num);
                        blindBoxOrderBaseTO.setOrderAmount(totalAmount);
                        long sub = userId % 1000000;
                        String orderSn = String.valueOf(orderId) + sub;
                        blindBoxOrderBaseTO.setOrderSn(orderSn);
                        blindBoxOrderBaseTO.setUserId(userId);
                        blindBoxOrderBaseTO.setOrderType(SmsCommonConstant.PANIC_PURCHASE);
                        blindBoxOrderBaseTO.setOrderNum(panicPurchaseVO.getPurchaseNum());

                        rabbitTemplate.convertAndSend(RabbitConstant.ORDER_EXCHANGE, RabbitConstant.PANIC_PURCHASE_KEY, blindBoxOrderBaseTO);
                        //发送死信队列
                        rabbitTemplate.convertAndSend(RabbitConstant.ORDER_EXCHANGE, RabbitConstant.PANIC_PURCHASE_DELAY_KEY, blindBoxOrderBaseTO);

                        PanicPurchaseResVO panicPurchaseResVO = new PanicPurchaseResVO();
                        panicPurchaseResVO.setOrderSn(orderSn);
                        panicPurchaseResVO.setProductType(SmsCommonConstant.BLIND_BOX);
                        return R.ok(panicPurchaseResVO);
                    }
                } else {
                    return R.failed(SmsErrorCode.OUT_OF_TEAM.getCode(), SmsErrorCode.OUT_OF_TEAM.getMsg());
                }
            } else {
                return R.failed(SmsErrorCode.PURCHASE_NOT_START.getCode(), SmsErrorCode.PURCHASE_NOT_START.getMsg());
            }
        }
        return R.failed();
    }

    /**
     * 新增描述信息
     *
     * @param panicPurchaseVO
     * @return
     */
    @Inner
    @PostMapping("/addNewPanicPurchase")
    public R<String> addNewPanicPurchase(@Valid @RequestBody PanicPurchaseVO panicPurchaseVO) {
        PanicPurchaseEntity panicPurchaseEntity = new PanicPurchaseEntity();
        BeanUtil.copyProperties(panicPurchaseVO, panicPurchaseEntity);
        panicPurchaseEntity.setStatus(SmsCommonConstant.ENABLE);
        panicPurchaseService.save(panicPurchaseEntity);
        return R.ok();
    }

    @Inner
    @GetMapping("offPanicPurchase/{id}")
    public R<String> offPanicPurchase(@PathVariable Long id) {
        LambdaUpdateWrapper<PanicPurchaseEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper
                .eq(PanicPurchaseEntity::getProductId, id)
                .eq(PanicPurchaseEntity::getProductType, SmsCommonConstant.COLLECTION)
                .set(PanicPurchaseEntity::getStatus, SmsCommonConstant.DISABLE);
        panicPurchaseService.update(updateWrapper);
        return R.ok();
    }
}